home *** CD-ROM | disk | FTP | other *** search
- *****Listing 5*****
-
- /*
- * life.c
- * copyright 1985,1988 Ronald Florence
- *
- * compile: cc -O -s life.c keys.c -lcurses -ltermcap -o life
- */
-
-
- #include <curses.h>
- #include <signal.h>
- #ifndef KEY_DOWN
- #include "keys.h"
- #endif
-
- #define ESC 0x1b
- #define life '@'
- #define crowd (life + 4)
- #define lonely (life + 2)
- #define birth (' ' + 3)
- #define minwrap(a,d) a = --a < 0 ? d : a
- #define maxwrap(a,d) a = ++a > d ? 0 : a
- #define wrap(a,z) if (a < 0) (a) += z; \
- else if (a > z) (a) = 1; \
- else if (a == z) (a) = 0
- #define MAXX (COLS-1)
- #define MAXY (LINES-3)
- #define boredom 5
-
- typedef struct node
- {
- int y, x;
- struct node *prev, *next;
- } LIFE;
-
- struct
- {
- int y, x;
- } pos[8] = { { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1},
- {-1, 1}, {-1, 0}, {-1,-1}, { 0,-1}
- };
-
- LIFE *head, *tail;
-
- extern char *malloc();
- char
- *rules[] = {
- " ",
- "The Rules of Life:",
- " ",
- " 1. A cell with more than three neighbors dies of overcrowding.",
- " 2. A cell with less than two neighbors dies of loneliness.",
- " 3. A cell is born in an empty space with exactly three neighbors.",
- " ",
- 0
- },
-
- *rules2[] = {
- "Use the arrow keys or the vi cursor keys",
- "(H = left, J = down, K = up, L = right)",
- "to move the cursor around the screen.",
- "The spacebar creates and destroys life.",
- "<Esc> starts the cycle of reproduction.",
- "<Del> ends life.",
- " ",
- "Press any key to play The Game of Life.",
- 0
- };
-
-
- main(ac, av)
- int ac;
- char **av;
- {
- int i = 0, k, die();
-
- initscr();
- crmode();
- noecho();
- signal(SIGINT, die);
- lookupkeys();
- head = (LIFE *)malloc(sizeof(LIFE));
- tail = (LIFE *)malloc(sizeof(LIFE)); /* lest we have an unanchored pointer */
- head->next = tail;
- tail->prev = head;
-
- if (ac > 1)
- readfn(*++av);
- else
- {
- erase();
- if (COLS > 40)
- for ( ; rules[i]; i++)
- mvaddstr(i+1, 0, rules[i]);
- for (k = 0; rules2[k]; k++)
- mvaddstr(i+k+1, 0, rules2[k]);
- refresh();
- while (!getch())
- ;
- setup();
- }
- nonl();
- while (TRUE)
- {
- display();
- mark_life();
- update();
- }
- }
-
-
- die()
- {
- signal(SIGINT, SIG_IGN);
- move(LINES-1, 0);
- refresh();
- endwin();
- exit(0);
- }
-
-
- kill_life(ly, lx)
- register int ly, lx;
- {
- register LIFE *lp;
-
- for (lp = head->next; lp != tail; lp = lp->next)
- if (lp->y == ly && lp->x == lx)
- {
- lp->prev->next = lp->next;
- lp->next->prev = lp->prev;
- free(lp);
- break;
- }
- }
-
-
- display()
- {
- int pop = 0;
- static int gen, oldpop, boring;
- char c;
- register LIFE *lp;
-
- erase();
- for(lp = head->next; lp != tail; lp = lp->next)
- {
- mvaddch(lp->y, lp->x, life);
- pop++;
- }
- if (pop == oldpop)
- boring++;
- else
- {
- oldpop = pop;
- boring = 0;
- }
- move(MAXY+1, 0);
- if (!pop)
- {
- printw("Life ends after %d generations.", gen);
- die();
- }
- printw("generation - %-4d", ++gen);
- printw(" population - %-4d", pop);
- refresh();
- if (boring == boredom)
- {
- mvprintw(MAXY, 0, "Population stable. Abort? ");
- refresh();
- while (!(c = getch()))
- ;
- if (toupper(c) == 'Y')
- die();
- }
- }
-
-
- mark_life()
- {
- register k, ty, tx;
- register LIFE *lp;
-
- for (lp = head->next; lp; lp = lp->next)
- for (k = 0; k < 8; k++)
- {
- ty = lp->y + pos[k].y;
- wrap(ty, MAXY);
- tx = lp->x + pos[k].x;
- wrap(tx, MAXX);
- stdscr->_y[ty][tx]++;
- }
- }
-
-
- update()
- {
- register int i, j, c;
-
- for (i = 0; i <= MAXY; i++)
- for (j = 0; j <= MAXX; j++)
- {
- c = stdscr->_y[i][j];
- if (c >= crowd || c >= life && c < lonely)
- kill_life(i, j);
- else if (c == birth)
- newlife(i, j);
- }
- }
-
-
- setup()
- {
- int x, y, c, start = 0;
-
- erase();
- y = MAXY/2;
- x = MAXX/2;
- while (!start)
- {
- move(y, x);
- refresh();
- switch (c = getkey())
- {
- case 'h' :
- case 'H' :
- case ('H' - '@'):
- case KEY_LEFT:
- case KEY_BACKSPACE:
- minwrap(x, MAXX);
- break;
- case 'j' :
- case 'J' :
- case ('J' - '@'):
- case KEY_DOWN:
- maxwrap(y, MAXY);
- break;
- case 'k' :
- case 'K' :
- case ('K' - '@'):
- case KEY_UP:
- minwrap(y, MAXY);
- break;
- case 'l' :
- case 'L' :
- case ('L' - '@'):
- case KEY_RIGHT:
- maxwrap(x, MAXX);
- break;
- case ' ' :
- if (inch() == life)
- {
- addch(' ');
- kill_life(y, x);
- }
- else
- {
- addch(life);
- newlife(y, x);
- }
- break;
- case 'q' :
- case 'Q' :
- case ESC :
- ++start;
- break;
- }
- }
- }
-
-
- newlife(ny, nx)
- int ny, nx;
- {
- LIFE *new;
-
- new = (LIFE *)malloc(sizeof(LIFE));
- new->y = ny;
- new->x = nx;
- new->next = head->next;
- new->prev = head;
- head->next->prev = new;
- head->next = new;
- }
-
-
- readfn(f)
- char *f;
- {
- FILE *fl;
- int y, x;
-
- if ((fl = fopen(f, "r")) == NULL)
- errx("usage: life [file (line/col pts)]\n", NULL);
- while (fscanf(fl, "%d%d", &y, &x) != EOF)
- {
- if (y < 0 || y > MAXY || x < 0 || x > MAXX)
- errx("life: invalid data point in %s\n", f);
- mvaddch(y, x, life);
- newlife(y, x);
- }
- fclose(fl);
-
- }
-
-
- errx(m,d)
- char *m, *d;
- {
- fprintf(stderr, m, d);
- endwin();
- exit(0);
- }
-